package Waya::App::CleanProblem;

# options:
#
#   --clean        clean nodes of unnecessary properties
#   --tr           handle correctness markup (see below)
#   --diff <x>     sets problem difficulty (PD[])
#   --type <x>     sets problem type (PT[])
#
# Files are edited in-place, so be sure to have a backup
# 
# Prepares a problem for use with kombilo. First we remove unnecessary
# properties in the game info and other nodes. In particular, we remove the
# CR[] properties automatically defined by cGoban 2. This means that there
# shouldn't be any regular CR[] markup, as it will be removed as well.
#
# Problems from goproblems.com (and other sources) have a 'RIGHT' in a leaf
# node comment if it is a correct solution. There's other markup, but that's
# not relevant here. We do things differently, however: We don't specify when
# a move is right, but when it's wrong (by using TR[]). So we convert one
# format to the other. Here is the algorithm we use:
#
# - Assume all nodes have a correctness status of 'unknown'
# - Traverse all nodes
#   - If the node is a leaf and has a comment containing 'RIGHT', mark the
#     node and all its predecessors as correct
#   - If the node is a leaf and does not have a 'RIGHT' comment, mark the node
#     and all its predecessors as wrong - but stop at nodes marked correct
#     already. That is, 'correct' overrides 'wrong'
#
# Now we we have a node tree in which each node is marked as belonging to a
# correct or to an incorrect path. Next:
#
# - Traverse all nodes again. If you find a node marked wrong, add a triangle
#   markup (TR[]) and prune this variation.
# 
# There is no need to remove the correct/wrong markers from nodes, as they
# won't affect the resulting SGF (they're usually private hash keys starting
# with an underscore, although for debugging purposes you might want to set
# PATH_KEY to something looking like an SGF property (e.g., 'XX') to see the
# results in SGF output)

use warnings;
use strict;
use Waya::Constants ':traverse';

our $VERSION = '0.1';

use base 'Waya::App::FileIterator';


use constant GETOPT     => (qw/tr clean PD=s PT=s/);
use constant PATH_KEY   => '_problem';
use constant PATH_RIGHT =>  1;
use constant PATH_WRONG => -1;


sub process_game {
    my $self = shift;
    $self->opt->{clean} && $self->clean_nodes;
    $self->opt->{tr}    && $self->convert_correctness;
    $self->apply_game_info_option(qw/PT PD/);
}


sub clean_nodes {
    my $self = shift;

    my $info = $self->game->game_info_node;
    delete $info->{$_} for
        qw/FF RU HA KM PW PB BR WR DT SY TM AP GN US SO GC EV ST CA PC RE OT/;

    $self->game->traverse_node(sub {
        my $node = shift;
        delete $node->{$_} for qw/CR MN DM FG RG CP/;
        RC_CONTINUE;
    });
}


sub convert_correctness {
    my $self = shift;

    $self->game->traverse_node(sub {
        my $node = shift;
        return RC_CONTINUE unless $node->is_leaf;

        my $markup;

        if (index($node->{C} || '', 'RIGHT') != -1) {
            $markup = PATH_RIGHT;
            $node->{C} =~ s/\s*RIGHT\s*//g;
            delete $node->{C} if $node->{C} =~ /^\s*$/;
        } else {
            $markup = PATH_WRONG;
        }

        while (1) {
            $node->{PATH_KEY()} = $markup;
            $node = $node->{prev};
            last if ($node->{PATH_KEY()} || 0) == PATH_RIGHT;
            last if $node->is_game_info_node;
        }

        return RC_CONTINUE;
    });

    $self->game->traverse_node(sub {
        my $node = shift;
        my $markup = $node->{PATH_KEY()};
        return RC_CONTINUE unless defined $markup;
        return RC_CONTINUE if $markup == PATH_RIGHT;
        $node->{TR} = $node->move;
        return RC_PRUNE;
    });

    # print $self->game->as_sgf; exit;
}


1;
